package com.freewater.springboot.demo.aop.example;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.dao.PessimisticLockingFailureException;

/**
 * Note that the aspect implements the Ordered interface so that we can set the precedence
 * of the aspect higher than the transaction advice (we want a fresh transaction each time we retry).
 */
@Aspect
public class ConcurrentOperationExecutor implements Ordered {

    public static final int DEFAULT_MAX_RETRIES = 2; // 实现Ordered接口，让每一次重试都在新的事务中进行

    private int maxRetries = DEFAULT_MAX_RETRIES;

    private int order;


    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    @Pointcut("execution(public * com.freewater.springboot.demo.aop.example.SomeBusinessService.*(..)) && @annotation(Idempotent)")
    public void serviceIdempotentMethod() {

    }

    @Around("serviceIdempotentMethod()")
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
        int numberRetried = 0;
        PessimisticLockingFailureException lockingFailureException;
        do {
            try {
                if (numberRetried > 0) {
                    System.out.println("retry " + numberRetried + " ....");
                }
                return pjp.proceed();
            } catch (PessimisticLockingFailureException e) {
                lockingFailureException = e;
                numberRetried++;
            }
        } while (numberRetried <= maxRetries);
        throw lockingFailureException;
    }

}
